package com.sk.bilibili.apiMapper.component;


import com.sk.bilibili.apiMapper.annotation.FieldPath;
import com.sk.bilibili.apiMapper.annotation.TypeConverter;
import com.sk.bilibili.apiMapper.bean.FieldInfo;
import com.sk.bilibili.apiMapper.interfaces.StringConverter;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 邵康
 * @date 2021/7/11 16:39
 */
public class FieldInfoCache {

    private Map<Class, List<FieldInfo>> cache;
    private List<StringConverter> converters;
    private StringConverterCache stringConverterCache;

    public void setConverters(List<StringConverter> converters) {
        this.converters = converters;
    }

    public FieldInfoCache() {
        cache=new HashMap<>();
        stringConverterCache=new StringConverterCache();
    }

    public List<FieldInfo> getFieldInfo(Class clazz) {
        if(!cache.containsKey(clazz)){
            cache.put(clazz,createFieldInfo(clazz));
        }
        return cache.get(clazz);
    }

    private List<FieldInfo> createFieldInfo(Class<?> clazz) {
        Field[] fields = clazz.getDeclaredFields();
        String basePath=null;
        FieldPath fieldPath = clazz.getAnnotation(FieldPath.class);
        if(fieldPath!=null)basePath=fieldPath.value();
        List<FieldInfo> res=new ArrayList<>();
        for (Field field : fields) {
            fieldPath = field.getAnnotation(FieldPath.class);
            String path=field.getName();
            boolean collection=false;
            if(fieldPath!=null){
                if(fieldPath.ignore())continue;
                collection=fieldPath.collection();
                if(!fieldPath.value().equals(""))path=fieldPath.value();
            }
            FieldInfo fieldInfo = new FieldInfo();
            if(basePath!=null)path=basePath+"."+path;
            String[] split = path.split("\\.");
            clazz=field.getType();
            fieldInfo.setField(field);
            fieldInfo.setCollection(collection);
            fieldInfo.setPaths(split);
            fieldInfo.setClazz(clazz);
            if(!collection){
                TypeConverter typeConverter = field.getAnnotation(TypeConverter.class);
                if(typeConverter!=null){
                    fieldInfo.setConverter(stringConverterCache.getStringConverter(typeConverter.value()));
                }else {
                    for (StringConverter converter:converters){
                        if(converter.support(clazz)){
                            fieldInfo.setConverter(converter);
                            break;
                        }
                    }
                }
            }
            fieldInfo.init();
            res.add(fieldInfo);
        }
        return res;
    }

}
